/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package password;

import amount.*;
import consecutive.DigitConsecutive;
import consecutive.LowerCaseConsecutive;
import consecutive.UpperCaseConsecutive;
import java.util.ArrayList;
import length.Length02;
import rule.Rule;
import score.DefaultScore;
import score.LengthDependedScore;
import score.UniqueTypeScore;
import score.WeightedScore;
import sequence.Sequence;

/**
 *
 * @author Daniel Gribel
 */
public class PasswordChecker02 {
    public static final String VERY_WEAK = "Very weak";
    public static final String WEAK = "Weak";
    public static final String MEDIUM = "Medium";
    public static final String STRONG = "Strong";
    public static final String VERY_STRONG = "Very strong";
   
    public static final String[] classification = {VERY_WEAK, WEAK, MEDIUM, STRONG, VERY_STRONG};
    public static final int[] interval = {20, 40, 60, 80, Integer.MAX_VALUE};
    
    private ArrayList<Rule> rules;
    private int checkerScore;
    private String result;
    private Length02 length;
    
    public PasswordChecker02() {
        super();
        this.rules = new ArrayList<Rule>();
        this.checkerScore = 0;
        appendRules();
    }
    
    private void appendRules() {
        length = new Length02(new DefaultScore());
        
        this.rules.add(new LowerCaseAmount(new LengthDependedScore(length, 2), "lowercase letters"));
        this.rules.add(new UpperCaseAmount(new LengthDependedScore(length, 2), "uppercase letters"));
        this.rules.add(new DigitAmount(new WeightedScore(4), "digits"));
        this.rules.add(new SymbolAmount(new WeightedScore(6), "symbols"));
        
        this.rules.add(new MidCharAmount(new WeightedScore(2), "mid chars"));
        
        this.rules.add(new LowerCaseConsecutive(new WeightedScore(2), "consecutive lowercase letters"));
        this.rules.add(new UpperCaseConsecutive(new WeightedScore(2), "consecutive uppercase letters"));
        this.rules.add(new DigitConsecutive(new WeightedScore(2), "consecutive digits"));
        
        this.rules.add(new DigitAmount(new UniqueTypeScore(length), "only digits"));
        this.rules.add(new LetterAmount(new UniqueTypeScore(length), "only letters"));
        
        String sAlphas = "abcdefghijlmnopqrstuvwxyz";
        String sNumerics = "01234567890";
        String sSymbols = ")!@#$%^&*()";
        
        this.rules.add(new Sequence(new WeightedScore(3), sAlphas, "alpha sequence"));
        this.rules.add(new Sequence(new WeightedScore(3), sNumerics, "digit sequence"));
        this.rules.add(new Sequence(new WeightedScore(3), sSymbols, "symbol sequence"));
        
        // the other rules were not implemented yet -- Daniel :(
        
    }
    
    public void checkPassword(String password) {
        
        String handledPassword = password.replaceAll("\\s+", "");
        
        length.calculate(handledPassword);
        checkerScore = length.getScore().getFinalScore();
        
        System.out.println("length: +" + length.getScore().getFinalScore());
        
        for(Rule rule : this.rules) {
            rule.checkConditions(handledPassword);
            rule.applyScore();
            this.checkerScore = this.checkerScore + rule.getScore().getFinalScore();
            
            if(rule.getScore().getFinalScore() >= 0)
                System.out.println(rule.getName() + ": +" + rule.getScore().getFinalScore());
            else System.out.println(rule.getName() + ": " + rule.getScore().getFinalScore());
        }
        result = classify();
        printResult();
    }
	
    private String classify() {
        for(int i = 0; i < classification.length; i++) {
            if(checkerScore < interval[i])
                return classification[i];
        }
        return VERY_STRONG;
    }
   
    private void printResult() {
        if(checkerScore < 0)
            checkerScore = 0;
        if(checkerScore > 100)
            checkerScore = 100;
        System.out.println("Strength score: " + checkerScore + "%");
        System.out.println("Strength verdict: " + result);
    }

    public int getCheckerScore() {
        return checkerScore;
    }

    public String getResult() {
        return result;
    }
}
